home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 June
/
CHIP Haziran 2001.iso
/
prog
/
haziran
/
19
/
setup.exe
/
data.z
/
pci_dma.c
< prev
next >
Wrap
C/C++ Source or Header
|
2001-04-11
|
8KB
|
262 lines
////////////////////////////////////////////////////////////////
// File - PCI_DMA.C
//
// This is a skeleton driver for a PCI card with Bus Master DMA.
// The driver implemets PCI detection, accessing memory mapped
// ranges on the card, and interrupt handler installation.
//
// It is recommended to take a look at real-world samples of
// PCI Bus Master DMA, in /windrvr/amcc/lib/amcclib.c and
// /windrvr/v3/lib/pbclib.c.
//
////////////////////////////////////////////////////////////////
#include "../../include/windrvr.h"
#include <stdio.h>
// put your vendor_id & device_id here
enum {MY_VENDOR_ID = 0x1201};
enum {MY_DEVICE_ID = 0x0001};
// put the offset of the card's register for programing DMA here
enum {MY_REG_DMA_STATUS = 0x10};
enum {MY_REG_DMA_PAGES = 0x100};
void MY_CardMainDriver()
{
// put your device driver code here
}
/////////////////////////////////////
// global variables section G_xxxx
/////////////////////////////////////
enum {INVALID_RES = 0xffff};
HANDLE hWD;
WD_CARD_REGISTER G_cardReg;
// index to resource in card of memory region & interrupt
// if you have more than one memory region, interrupt or have an IO range,
// add more indexes here, and locate them in IO_DetectCardElements() function.
DWORD G_resMemory;
// base address for memory mapped region
DWORD G_baseMemory;
DWORD G_baseMemoryTrns;
void IO_Open()
{
WD_VERSION ver;
hWD = INVALID_HANDLE_VALUE;
hWD = WD_Open();
// Check whether handle is valid and version OK
if (hWD==INVALID_HANDLE_VALUE)
{
printf("Failed opening " WD_PROD_NAME " device\n");
exit(1);
}
BZERO(ver);
WD_Version(hWD,&ver);
if (ver.dwVer<WD_VER)
{
printf("Incorrect " WD_PROD_NAME " version\n");
WD_Close(hWD);
exit(1);
}
G_cardReg.hCard = 0;
}
// IO_DetectCardElements() scans the card recourses (Interrupts, IO & memory mapped regions)
// and sets IO_ResInterrupt & IO_ResMemory to point to the correct element number
void IO_DetectCardElements()
{
DWORD i;
G_resMemory = INVALID_RES;
for (i=0; i<G_cardReg.Card.dwItems; i++)
{
switch(G_cardReg.Card.Item[i].item)
{
case ITEM_INTERRUPT:
printf("error - Card has an Interrupt\n");
exit(1);
break;
case ITEM_MEMORY:
if (G_resMemory==INVALID_RES)
G_resMemory = i;
else
{
printf("error - Card has more than one memory region\n");
exit(1);
}
break;
case ITEM_IO:
printf("error - Card has an IO ragne\n");
exit(1);
break;
}
}
if (G_resMemory==INVALID_RES)
{
printf("Memory region not found\n");
exit(1);
}
}
// IO_DetectCard() scans the PCI bus & detect the card
void IO_DetectCard()
{
WD_PCI_SCAN_CARDS pciScan;
WD_PCI_CARD_INFO pciCardInfo;
BZERO(pciScan);
pciScan.searchId.dwVendorId = MY_VENDOR_ID;
pciScan.searchId.dwDeviceId = MY_DEVICE_ID;
WD_PciScanCards (hWD, &pciScan);
if (pciScan.dwCards==0) // Found at least one card
{
printf("Could not find PCI card\n");
exit(1);
}
BZERO(pciCardInfo);
pciCardInfo.pciSlot = pciScan.cardSlot[0];
WD_PciGetCardInfo (hWD, &pciCardInfo);
// the info for Card comes from WD_PciGetCardInfo()
// for PCI cards. for ISA cards the information has to be
// set by the user (IO/memory address & interrupt number).
BZERO(G_cardReg);
G_cardReg.Card = pciCardInfo.Card;
IO_DetectCardElements();
G_cardReg.fCheckLockOnly = FALSE;
WD_CardRegister (hWD, &G_cardReg);
if (G_cardReg.hCard==0)
{
printf ("Failed locking device\n");
exit(1);
}
G_baseMemory = G_cardReg.Card.Item[G_resMemory].I.Mem.dwUserDirectAddr;
G_baseMemoryTrns = G_cardReg.Card.Item[G_resMemory].I.Mem.dwTransAddr;
}
void IO_Close()
{
// unregister card
if (G_cardReg.hCard)
WD_CardUnregister(hWD, &G_cardReg);
// close WinDriver
WD_Close(hWD);
}
// performs a single 32 bit read from memory mapped range
DWORD IO_Read32BitRegister(DWORD dwAddr)
{
PDWORD pDW = (PDWORD) (G_baseMemory + dwAddr);
return *pDW;
}
// performs a single 32 bit write to memory mapped range
void IO_Write32BitRegister(DWORD dwAddr, DWORD dwData)
{
PDWORD pDW = (PDWORD) (G_baseMemory + dwAddr);
*pDW = dwData;
}
// transfer data to/from PCI card using bus-master DMA.
// pBuffer if the data to transfer (or to receive data), dwBytes - size of data
// fIsRead is TRUE for read (PCI card --> system memory), or FALSE for write ( memory --> PCI card)
// addr local address on PCI card
void IO_DMATransferBuffer(PVOID pBuffer, DWORD dwBytes, BOOL fIsRead, DWORD dwAddr)
{
WD_DMA dma;
DWORD i;
DWORD dwSumBytes;
BZERO(dma);
dma.pUserAddr = pBuffer;
dma.dwBytes = dwBytes;
dma.dwOptions = 0;
// lock region in memory & get page list
WD_DMALock(hWD,&dma);
// program page transfer list on PCI bus master card
dwSumBytes = 0;
for (i=0; i<dma.dwPages; i++)
{
IO_Write32BitRegister(MY_REG_DMA_PAGES + i*12 + 0, (DWORD) dma.Page[i].pPhysicalAddr);
IO_Write32BitRegister(MY_REG_DMA_PAGES + i*12 + 4, dwAddr + dwSumBytes);
IO_Write32BitRegister(MY_REG_DMA_PAGES + i*12 + 8, dma.Page[i].dwBytes);
dwSumBytes += dma.Page[i].dwBytes;
}
// write the number of pages to transfer and direction of transfer
IO_Write32BitRegister(MY_REG_DMA_STATUS, dma.dwPages | (fIsRead ? 0x1000 : 0));
// wait for for status register to indicate transfer compleate here.
// you can use the interrupt routine for non-busy wait (if the card enables interrupt
// indication for end of transfer).
WD_DMAUnlock(hWD,&dma);
}
// transfer data to/from PCI card NOT using DMA.
// pBuffer if the data to transfer (or to receive data), dwBytes - size of data
// fIsRead is TRUE for read (PCI card --> system memory), or FALSE for write ( memory --> PCI card)
// addr local address on PCI card
void IO_TransferBuffer(PVOID pBuffer, DWORD dwBytes, BOOL fIsRead, DWORD dwAddr)
{
WD_TRANSFER trans;
BZERO(trans);
if (fIsRead)
trans.cmdTrans = RM_SDWORD; // Read Memory String DWORD
else trans.cmdTrans = WM_SDWORD; // Write Memory String DWORD
trans.dwPort = G_baseMemoryTrns + dwAddr;
trans.Data.pBuffer = pBuffer;
trans.dwBytes = dwBytes;
// if fAutoinc==TRUE then read/write will run through an address range on the card
// if fAutoinc==FALSE then read/write will perform on the same address of the card
// (usually used for FIFO where all reads/writes are to the same register)
trans.fAutoinc = TRUE;
trans.dwOptions = 0;
WD_Transfer (hWD, &trans);
// this function could also be implemeted directly with memcpy().
// for example, to read a memory region:
// memcpy (pBuffer, (PVOID) (dwAddr + G_baseMemory), dwBytes);
}
int main(int argc, char *argv[])
{
IO_Open();
IO_DetectCard();
// call your main card routine program
// in your program you can use IO_DMATransferBuffer() for DMA read/write,
// or IO_TransferBuffer() to do the same thing without DMA,
// IO_Read32BitRegister() & IO_Write32BitRegister for single 32bit read/write
MY_CardMainDriver();
IO_Close();
return 0;
}